package cn.tk.engine.mr;

import cn.tk.cache.mr.FlowBuf;
import cn.tk.model.entity.mr.Flow;
import cn.tk.model.entity.mr.GlobalReply;
import cn.tk.model.pojo.mr.engine.MrReply;
import cn.tk.model.pojo.mr.engine.ReplyNodeJump;
import cn.tk.model.pojo.mr.flow.*;
import cn.tk.service.mr.GlobalReplyService;
import cn.tk.service.mr.ReplyNodeService;
import cn.tk.utils.EmptyUtil;
import com.google.common.collect.Lists;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by denglw on 2021/8/6.<br/>
 * Desc: 话术节点逻辑处理
 */
@Slf4j
@Component
public class ReplyNodeDeal {

    @Autowired
    private ReplyNodeService replyNodeService;

    @Autowired
    private GlobalReplyService globalReplyService;

    /**
     * 话术节点跳转行为判断.<br/>
     * @param nodeId 话术节点id
     * @return 跳转行为
     */
    public ReplyNodeJump jumpOut(Long nodeId) {
        ReplyNodeAction action = replyNodeService.replyNodeAction(nodeId);
        if (action == null) {
            return null;
        }
        boolean ifJump = Objects.equals(action.getActionType(), 2);
        ReplyNodeJump jump = new ReplyNodeJump();
        jump.setIfJump(ifJump);
        jump.setJumpFlowId(action.getJumpFlowId());
        jump.setJumpNodeId(action.getJumpNodeId());
        return jump;
    }

    /**
     * 话术节点求解话术.<br/>
     * @param flowId 流程id
     * @param nodeId 话术节点id
     * @param lastRepeatNum 之前该节点已经触发的次数
     * @return 话术
     */
    public MrReply explain(Long flowId, Long nodeId, int lastRepeatNum) {
        MrReply mrReply = MrReply.defaultReply();
        ReplyNodeDTO node = replyNodeService.getReplyNode(nodeId);
        if (node == null) {
            return mrReply;
        }
        // 获取全局话术: 超时话术及语音识别失败话术
        // 在超时话术层面：优先本话术节点的超时话术
        List<MrReply.TimeoutReply> timeoutReplies = new ArrayList<>();
        List<MrReply.VoiceNrReply> voiceNrReplies = new ArrayList<>();
        Map<Integer, List<InnerReply>> globalReplies = this.getGlobalReplies(flowId);
        List<ReplyNodeTimeout> timeouts = node.getTimeouts();
        if (!EmptyUtil.emptyColl(timeouts)) {
            timeouts.sort(Comparator.comparing(ReplyNodeTimeout::getSortNum));
            for (ReplyNodeTimeout timeout : timeouts) {
                MrReply.TimeoutReply i = new MrReply.TimeoutReply();
                i.setTimeout(timeout.getTimeout());
                i.setReply(replyNodeService.getReply(timeout.getReplyId()));
                timeoutReplies.add(i);
            }
        } else {
            for (InnerReply innerReply : EmptyUtil.nullToEmptyList(globalReplies.get(2))) {
                MrReply.TimeoutReply i = new MrReply.TimeoutReply();
                i.setTimeout(innerReply.getTimeoutSecond());
                i.setReply(innerReply.getReply());
                timeoutReplies.add(i);
            }
        }
        // 设置语音识别失败话术
        for (InnerReply innerReply : EmptyUtil.nullToEmptyList(globalReplies.get(3))) {
            MrReply.VoiceNrReply i = new MrReply.VoiceNrReply();
            i.setReply(innerReply.getReply());
            voiceNrReplies.add(i);
        }
        mrReply.setTimeoutReplies(timeoutReplies);
        mrReply.setVoiceNrReplies(voiceNrReplies);
        // 是否监听键盘
        Integer listener = node.getListener();
        mrReply.setKeyboardListened(Objects.equals(listener, 1));
        // 是否触发短信
        mrReply.setSmsSend(Objects.equals(node.getSmsSend(), true));
        // 封装常规回复话术
        if (!EmptyUtil.emptyColl(node.getFilters())) {
            List<String> filters = node.getFilters().stream().map(ReplyNodeFilter::getQuestion).collect(Collectors.toList());
            mrReply.setFilterQuestions(filters);
        }

        // 1、如果超出最大重复次数，结束会话：如果配置的重复次数是1，代表可以匹配2次
        boolean isOver = lastRepeatNum > node.getRepeatNum();
        if (isOver) {
            Long maxReplyId = node.getMaxRepeatReplyId();
            ReplyDTO reply = replyNodeService.getReply(maxReplyId);
            mrReply.setCustomReplies(Lists.newArrayList(reply));
            mrReply.setEndSession(true);
            return mrReply;
        }

        // 2、封装是否结束会话
        ReplyNodeAction action = node.getAction();
        if (action != null) {
            mrReply.setEndSession(Objects.equals(action.getActionType(), 3));
        }

        // 3、封装常规回复话术: 连贯话术  常规话术  跳回话术
        List<ReplyDTO> customReplies = new ArrayList<>();
        Long outterReplyId = node.getOutterReplyId();
        if (!EmptyUtil.nullOrZero(outterReplyId)) {
            ReplyDTO i = replyNodeService.getReply(outterReplyId);
            customReplies.add(i);
        }
        Long defaultReplyId = node.getDefaultReplyId();
        if (!EmptyUtil.nullOrZero(defaultReplyId)) {
            ReplyDTO i = replyNodeService.getReply(defaultReplyId);
            customReplies.add(i);
        }
        Long innerReplyId = node.getInnerReplyId();
        if (!EmptyUtil.nullOrZero(innerReplyId)) {
            ReplyDTO i = replyNodeService.getReply(innerReplyId);
            customReplies.add(i);
        }
        mrReply.setCustomReplies(customReplies);
        return mrReply;
    }

    /**
     * 获取流程所在bot的全局回复话术列表.<br/>
     * @param flowId 流程id
     * @return 全局话术
     */
    public Map<Integer, List<InnerReply>> getGlobalReplies(Long flowId) {
        FlowBuf flowBuf = FlowBuf.getInstance();
        Flow flow = flowBuf.getFlow(flowId);
        if (flow == null) {
            return new HashMap<>(4);
        }
        Long botId = flow.getBotId();
        List<GlobalReply> replies = globalReplyService.globalReplies(botId);
        if (EmptyUtil.emptyColl(replies)) {
            return new HashMap<>(4);
        }
        // 按类型分组
        Map<Integer, List<InnerReply>> map = new HashMap<>(8);
        replies.stream().collect(Collectors.groupingBy(GlobalReply::getEventType)).forEach((k, v) -> {
            List<InnerReply> innerReplies = new ArrayList<>();
            v.sort(Comparator.comparing(GlobalReply::getSortNum));
            for (GlobalReply i : v) {
                InnerReply innerReply = new InnerReply();
                Long replyId = i.getReplyId();
                innerReply.setReplyId(replyId);
                ReplyDTO reply = replyNodeService.getReply(replyId);
                innerReply.setReply(reply);
                innerReply.setTimeoutSecond(i.getTimeoutSecond());
                innerReply.setIntentId(i.getIntentId());
                innerReplies.add(innerReply);
            }
            map.put(k, innerReplies);
        });
        return map;
    }


    @Data @NoArgsConstructor
    static class InnerReply {
        /**
         * 回复话术id
         */
        private Long replyId;

        /**
         * 回复
         */
        private ReplyDTO reply;

        /**
         * 超时回复下，定义超时秒数
         */
        private Integer timeoutSecond;

        /**
         * 重述回复下：匹配的意图id
         */
        private Long intentId;
    }

}
